题解:P2318 [HNOI2005] 虚拟内存

封面

思路:

定义三个 unordered_map,两个 unordered_map 的键和值都是 int 类型,分别存被访问的次数定义名字为 mpmp 和是在什么时候存进来的定义名字为 jljl,第三个 unordered_map 的键为 int 类型,而值为 vector 数组,用来存访问次数为键的内存页是几定义名字为 sese

定义 cc 为需要访问的虚拟内存页的编号,再定义一个 minnminn 表示现在最少的访问次数。

如果要访问的内存页存在也就是 mp.count(c) 为一,那么让我们的答案加一,然后把 sese 里的数组里的 cc 删除,接着把 cc 加入到 sese 的键为这次操作后 cc 被访问的次数的数组里,然后判断一下在这次操作后原本 sese 的键为 minnminn 的数组大小是否为零,如果为零则代表 cc 原本是这个数组里唯一的元素,而 cc 的访问次数增加后,这个数组里就没有元素了,也就是最少的访问次数现在不是 minnminn 了而是 minnminn 加上一,我们让 minnminn 加一。

如果要访问的内存页不存在,则先判断一下现在 mpmp 里键的数量是否小于 nn
如果小于 nn,则把 mpcmp_c 赋值为一,然后将 jlcjl_c 赋值为现在是第几个操作,然后在 sese 里键为一的数组里加入 cc,最后把 minnminn 赋值为一,因为 cc 是刚刚加入的,所以只被访问了一次,是最少的访问次数。
如果不小于 nn 则把 sese 里键为 minnminn 的数组里的第一个值删除并把 cc 加入 sese 里键为一的数组里。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define itn int
#define ull unsigned long long
int n,m,ans=0;
unordered_map<int,int>mp;// 被访问的次数
unordered_map<int,int>jl;// 是在什么时候存进来的
unordered_map<int,vector<int> >se;// 访问次数,是什么
int minn=1e9;// 最少的访问次数
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
jl[int(1e9+1)]=m+1;
int c;
for(int i=1;i<=m;i++){
cin>>c;
if(mp.count(c)){
ans++;
auto it=find(se[mp[c]].begin(),se[mp[c]].end(),c);
se[mp[c]].erase(it);
if(se[minn].size()==0)minn++;
mp[c]++;
se[mp[c]].push_back(c);
}
else{
if(mp.size()<n){
mp[c]=1;
jl[c]=i;
se[mp[c]].push_back(c);
minn=1;
}
else{
int sanc=1e9+1;
auto it=se.begin();
vector<int>sz(se[minn]);
sanc=sz[0];
auto itt=find(se[mp[sanc]].begin(),se[mp[sanc]].end(),sanc);
se[mp[sanc]].erase(itt);
if(se[mp[sanc]].size()==0)se.erase(mp[sanc]);
mp.erase(sanc);
jl.erase(sanc);
mp[c]=1;
jl[c]=i;
minn=1;
se[mp[c]].push_back(c);
}
}
}
cout<<ans;
return 0;
}